//
//  Player_Model.m
//  ICE_Player
//
//  Created by lijinxin on 11-11-4.
//  Copyright (c) 2011年 __MyCompanyName__. All rights reserved.
//

#import <CoreFoundation/CoreFoundation.h>
#import "EkkVideoView.h"
#import "Player_Model.h"
#include "../../ekk_player_lib/inc/ekk_interface.h"
#include "../../ekk_player_lib/inc/ekk_audio/audio_service.h"

#define INVALID_VALUE (-1)

typedef enum {
    E_VM_NONE = 0,
    E_VM_PLAY,
    E_VM_COUNT,
}VERBOSE_MSG;

typedef struct tagMOVIE_INFO_PRIVATE{
    id target;
    SEL selector;
    id param;
    char* path;
    char* thumbnail_path; 
}MOVIE_INFO_PRIVATE;

@interface Player_MainThread_Handler : NSObject
{
    VERBOSE_MSG message;
    NSTimer* subtitle_timer;
    id myself;
}
@property VERBOSE_MSG message;
- (void)On_Handle_Verbose;
- (void)On_SetUpVideoView;
- (void)On_Handle_Movie_Info;
- (void)On_SetUp_Subtitle;
- (void)Start_Render_Subtitle;
- (void)On_Render_Subtitle;
- (void)On_Stop_Render_Subtitle;
- (void)On_Load_Url;
@end

static E_SCREEN_MODE g_cur_mode = EKK_VIDEO_NORMAL_SIZE;
static id g_cb_o[E_PCB_COUNT] = {0};
static SEL g_cb_f[E_PCB_COUNT] = {0};
static id g_cb_p[E_PCB_COUNT] = {0};
static BOOL g_inited = NO;
static E_PLAYER_STATE g_state = E_PS_NONE;
static EKK_OBJ_HANDLE g_player_obj = NULL;
static AUDIO_SERVICE_HANDLE g_audio_hdl = NULL;
static Player_MainThread_Handler* g_mr = NULL;
static EkkVideoView* g_view = NULL;
static BOOL g_rendered_video = NO;
static MOVIE_INFO g_cur_movie_info = {0};
static MOVIE_INFO_PRIVATE* g_cur_ctx = NULL;
static GMT_TASK_OUTPUT *g_task_output = NULL;
static BOOL g_hide_subtitle = NO;
static CGRect g_subtitle_bounds = {0};
static enum FontEffectType g_font_effect = kDefaultFont;
static unsigned long g_font_size = 18;
static unsigned long g_font_color = 0xFFFFFFFF;//White
static SUBTITLE_INFO g_subtitle_info = {0};
static long g_seeking_pos_in_sec = INVALID_VALUE;
static char g_cur_url[EKK_MAX_URL_LEN] = {0};
static BOOL g_should_resume_bg = NO;
static BOOL g_should_resume_ls = NO;
static long g_width = 0;
static long g_height = 0;

@interface Player_Model (PrivateMethods)

@end

@implementation Player_Model

static void video_open_handler(void* param, void* ekk_render_info);

static void setUpVideoView()
{
    CGRect video_rect = {0};
    CGRect view_rect = {0};
    long w = 0, h = 0;
    if (g_view && g_player_obj)
    {
        [g_view set_video_size_mode:0];
        view_rect = g_view.bounds;
        //view_rect.size.width = 1024.f;
        //view_rect.size.height = 1024.f;
        ekk_obj_get_video_height(g_player_obj, &h);
        ekk_obj_get_video_width(g_player_obj, &w);
        if (w > 0 && h > 0)
        {
            video_rect.size.height = (CGFloat)h;
            video_rect.size.width = (CGFloat)w;
        }
        else
        {
            video_rect = view_rect;
        }
        [g_view set_video_rect:&view_rect src_rect_name:&video_rect];
        [g_view restore_from_black];
        [g_view layoutSubviews];
    }
}

static void state_message_push_func(EKK_PLAYER_STATE old_state, EKK_PLAYER_STATE new_state, void *param, long err_code)
{
    NSObject* obj = NULL;
    SEL sel;
    NSObject* ns_param = NULL;
    E_PLAYER_CALLBACK callback_id = E_PCB_NONE;
    if (err_code != EKK_ERROR_NONE)
    {
        if (err_code == EKK_ERROR_PLAYER_EOF)
        {
            callback_id = E_PCB_END;
            g_state = E_PS_END;
        }
        else
        {
            callback_id = E_PCB_ERROR;
        }
    }
    if (callback_id == E_PCB_NONE)
    {
        switch (new_state)
        {
            case EKK_PS_OPENED:
                callback_id = E_PCB_LOADED;
                g_mr.message = E_VM_PLAY;
                [g_mr performSelectorOnMainThread:@selector(On_SetUp_Subtitle) withObject:(id)nil waitUntilDone:YES];
                [g_mr performSelectorOnMainThread:@selector(On_Handle_Verbose) withObject:(id)nil waitUntilDone:YES];
                if (g_view && g_player_obj)
                {
                    {
                        long w = 0, h = 0;
                        ekk_obj_get_video_height(g_player_obj, &h);
                        ekk_obj_get_video_width(g_player_obj, &w);
                        g_width = w;
                        g_height = h;
                        if (w <= 0 || h <= 0)
                        {
                            video_open_handler(NULL, NULL);
                        }
                    }
                }
                break;
            case EKK_PS_PLAY:
                callback_id = E_PCB_START_PLAY;
                g_state = E_PS_PLAYING;
                g_seeking_pos_in_sec = INVALID_VALUE;
                break;
            case EKK_PS_PAUSE:
                callback_id = E_PCB_PAUSED;
                g_state = E_PS_PAUSED;
                g_seeking_pos_in_sec = INVALID_VALUE;
                break;
            case EKK_PS_CLOSING:
                //callback_id = E_PCB_LOADED;
                [g_mr performSelectorOnMainThread:@selector(On_Stop_Render_Subtitle) withObject:(id)nil waitUntilDone:YES];
                g_state = E_PS_CLOSING;
                g_seeking_pos_in_sec = INVALID_VALUE;
                break;
            case EKK_PS_CLOSED:
                callback_id = E_PCB_CLOSED;
                g_state = E_PS_READY;
                g_seeking_pos_in_sec = INVALID_VALUE;
                g_width = 0;
                g_height = 0;
                break;
            case EKK_PS_SET_PLAY_EFFECT:
                //callback_id = E_PCB_LOADED;
                break;
            case EKK_PS_RESTART_AUDIO_SERVICE:
                //callback_id = E_PCB_LOADED;
                break;
            default:
                break;
        }
    }
    if (callback_id != E_PCB_NONE)
    {
        obj = g_cb_o[callback_id];
        sel = g_cb_f[callback_id];
        ns_param = g_cb_p[callback_id];
        [(NSObject*)(obj) performSelectorOnMainThread:sel withObject:ns_param waitUntilDone:YES];
    }
}

static void video_open_handler(void* param, void* ekk_render_info)
{
    //set up video view, must in mainthread
    if (g_mr)
    {
        [g_mr performSelectorOnMainThread:@selector(On_SetUpVideoView) withObject:nil waitUntilDone:YES];
    }
    g_rendered_video = NO;
}

static void video_close_handler(void* param, void* ekk_render_info)
{
	g_rendered_video = YES;
}

static void video_render_handler(void* param, void* ekk_render_info)
{
	EKK_RENDER_INFO *render_info = (EKK_RENDER_INFO *)ekk_render_info;
	EKK_LINSIZE lsz = {0};
	
    if (g_view)
    {
        if(render_info->buffer_len != 0 && NULL != render_info->buffer_addr)
        {
            ekk_obj_get_video_linesize(g_player_obj, &lsz);
            g_rendered_video = YES;
            [g_view render_video:render_info->buffer_addr buffer_len:render_info->buffer_len y:lsz.linesize_y u:lsz.linesize_u v:lsz.linesize_v];
        }
        else if(g_rendered_video)
        {
            [g_view refresh_video];
        }
    }
}

static void video_set_ps(void* param, void* ekk_render_info)
{
	EKK_RENDER_INFO *render_info = (EKK_RENDER_INFO *)ekk_render_info;
	
	//set_window_video_ps((WINDOW)player->_wnd, render_info->brightness, render_info->contrast, render_info->saturation);
}

static void audio_open_handler(void* param, void* ekk_render_info)
{
	int sample = 0;
	int channel = 0;
    
    if (!g_audio_hdl)
    {
        init_audio_service();
        g_audio_hdl = create_audio_service(0, 0, 16);
		ekk_obj_get_audio_sample_rate(g_player_obj, &sample);
		ekk_obj_get_audio_num_of_channels(g_player_obj, &channel);
		set_audio_service_samplerate(g_audio_hdl, sample);
		set_audio_service_channels(g_audio_hdl, channel);
	}
}

static void audio_close_handler(void* param, void* ekk_render_info)
{
	if (g_audio_hdl)
	{
		destroy_audio_service(g_audio_hdl);
		g_audio_hdl = NULL;
		uninit_audio_service();
	}
    
}

static void audio_render_handler(void* param, void* ekk_render_info)
{
	EKK_RENDER_INFO *render_info = (EKK_RENDER_INFO*)ekk_render_info;	
	int res = 0;
    
    //	return SUCCESS;
	
	if (render_info->buffer_len > 0 && g_audio_hdl)
	{
		res = play_audio_buffer(g_audio_hdl, render_info->buffer_addr, render_info->buffer_len, render_info->ts);
		render_info->render_result = res;
		if (0 != res)
		{
			printf("error play_audio_buffer \n");
		}
	}
}

static void audio_get_ts_handler(void* param, void* ekk_render_info)
{
	EKK_RENDER_INFO *render_info = (EKK_RENDER_INFO*)ekk_render_info;	
    
    if(!g_player_obj)
	{
		render_info->ts = 0;
	}
	else
	{
		render_info->ts = get_audio_service_ts(g_audio_hdl);
	}
}

static void audio_get_frame_count_handler(void* param, void* ekk_render_info)
{
	EKK_RENDER_INFO *render_info = (EKK_RENDER_INFO*)ekk_render_info;	
    
	if(!g_player_obj)
	{
		render_info->frame_count = 0;
	}
	else
	{
		render_info->frame_count = get_audio_service_frame_count(g_audio_hdl);
	}
}

static void audio_get_play_state_handler(void* param, void* ekk_render_info)
{
	EKK_RENDER_INFO *render_info = (EKK_RENDER_INFO*)ekk_render_info;	
    
	if(!g_player_obj)
	{
		render_info->play_state = 0;
	}
	else
	{
		render_info->play_state = get_audio_service_play_state(g_audio_hdl);
	}
}

static void audio_flush_handler(void* param, void* ekk_render_info)
{
	if (g_player_obj)
	{
		empty_audio_buffer(g_audio_hdl);
	}
}

static void audio_replay(void* param, void* ekk_render_info)
{
	if (g_player_obj)
	{
		replay_audio_service(g_audio_hdl);
	}
}

static void audio_pause(void* param, void* ekk_render_info)
{
	if (g_player_obj)
	{
		pause_audio_service(g_audio_hdl);
	}
}

static void audio_set_ps(void* param, void* ekk_render_info)
{
	EKK_RENDER_INFO *render_info = (EKK_RENDER_INFO *)ekk_render_info;
	
	if (g_player_obj)
	{
		set_audio_service_play_speed(g_audio_hdl, render_info->play_speed);
	}
}

+ (BOOL)Init
{
    if (!g_inited && ekk_obj_init(NULL) == EKK_ERROR_NONE)
    {
        //ekk init succeed
        g_state = E_PS_READY;
        g_cur_mode = E_SCM_WIDTH_ADJUSTED;
        memset(g_cb_o, 0, sizeof(g_cb_o));
        memset(g_cb_f, 0, sizeof(g_cb_f));
        memset(g_cb_p, 0, sizeof(g_cb_p));
        g_mr = [[Player_MainThread_Handler alloc] init];
        ekk_gmt_init();
        g_inited = YES;
        return TRUE;
    }
    g_inited = NO;
    return FALSE;
}

+ (void)Un_Init
{
    if (g_inited)
    {
        ekk_gmt_uninit();
        if (g_mr)
        {
            [g_mr release];
            g_mr = NULL;
        }
        ekk_obj_uninit();
        g_state = E_PS_NONE;
        g_inited = NO;
    }
}

+ (BOOL)Load:(char*)url
{
    if (!g_inited || !url || !g_mr)
    {
        return FALSE;
    }
    strcpy(g_cur_url,url);
    [g_mr On_Load_Url];
    return TRUE;
}

+ (void)Get_Info:(PLAYER_INFO*)info
{
    long long t = 0;
    if (info)
    {
        memset(info, 0, sizeof(PLAYER_INFO));
        if (g_player_obj)
        {
            ekk_obj_get_file_len_by_second(g_player_obj, &t);
            info->file_len_sec = (long)t;
            if (g_state == E_PS_PAUSED || g_state == E_PS_PLAYING)
            {
                ekk_obj_get_play_pos_by_second(g_player_obj, &t);
                info->cur_play_sec = g_seeking_pos_in_sec == INVALID_VALUE ? (long)t : g_seeking_pos_in_sec;
            }
            else
            {
                info->cur_play_sec = 0;
            }
            info->width = g_width;
            info->height = g_height;
        }
        info->volume = get_audio_service_volume() * 100.f;
        info->screen_mode = g_cur_mode;
    }
    
}

+ (BOOL)Close
{
    if (g_player_obj)
    {
        if (g_view)
        {
            [g_view clear_to_black];
        }
        ekk_obj_close(g_player_obj);
        g_player_obj = NULL;
        return YES;
    }
    return NO;
}

+ (void)Pause
{
    if (g_player_obj)
    {
        ekk_obj_pause(g_player_obj);
    }
}

+ (void)Play
{
    if (g_player_obj)
    {
        if (g_state == E_PS_END)
        {
            ekk_obj_seek(g_player_obj, 0);
        }
        ekk_obj_play(g_player_obj);
    }
}

+ (long)Seek:(long)second
{
    long long flen = 0;
    if (g_player_obj)
    {
        ekk_obj_get_file_len_by_second(g_player_obj, &flen);
        if (flen > 0)
        {
            g_seeking_pos_in_sec = second;
            second = second > flen ? flen : (second < 0 ? 0 : second);
            ekk_obj_seek(g_player_obj, second);
        }
    }
    return second;
}

+ (void)setRenderView:(UIView*)view
{
    g_view = (EkkVideoView*)view;
    CGRect bounds = g_view.bounds;
    BOOL is_landscape = bounds.size.width > bounds.size.height ? YES : NO;
    if (bounds.size.width > 960.f || bounds.size.height > 960.f)
    {
        // for iPad
        g_font_size = 24;
        if (is_landscape)
        {
            g_subtitle_bounds.origin.x = bounds.size.width * 0.1;
            g_subtitle_bounds.origin.y = bounds.size.height * 0.8;
            g_subtitle_bounds.size.width = bounds.size.width * 0.8;
            g_subtitle_bounds.size.height = bounds.size.height * 0.2;
        }
        else
        {
            g_subtitle_bounds.origin.x = bounds.size.height * 0.1;
            g_subtitle_bounds.origin.y = bounds.size.width * 0.8;
            g_subtitle_bounds.size.width = bounds.size.height * 0.8;
            g_subtitle_bounds.size.height = bounds.size.width * 0.2;
        }
    }
    else
    {
        // for iPhone & thouch
        g_font_size = 18;
        if (is_landscape)
        {
            g_subtitle_bounds.origin.x = bounds.size.width * 0.1;
            g_subtitle_bounds.origin.y = bounds.size.height * 0.7;
            g_subtitle_bounds.size.width = bounds.size.width * 0.8;
            g_subtitle_bounds.size.height = bounds.size.height * 0.3;
        }
        else
        {
            g_subtitle_bounds.origin.x = bounds.size.height * 0.1;
            g_subtitle_bounds.origin.y = bounds.size.width * 0.7;
            g_subtitle_bounds.size.width = bounds.size.height * 0.8;
            g_subtitle_bounds.size.height = bounds.size.width * 0.3;
        }
    }
}

+ (float)set_Volume:(float)percents
{
    set_audio_service_volume(percents / 100.f);
    percents = get_audio_service_volume() * 100.f;
    return percents;
}

+ (float)get_Volume
{
    return get_audio_service_volume() * 100.f;
}

+ (void)set_Screen_Mode:(E_SCREEN_MODE)mode
{
    g_cur_mode = mode;
    if (g_view)
    {
        [g_view set_video_size_mode:g_cur_mode];
    }
}

+ (void)change_Screen_Mode
{
    [Player_Model set_Screen_Mode:((g_cur_mode + 1) % E_SCM_COUNT)];
}

+ (E_PLAYER_STATE)get_State
{
    return g_state;
}

+ (void)set_CallBack:(E_PLAYER_CALLBACK)type target:(id)object callback:(SEL)func withObject:(id)parameter
{
    g_cb_o[type] = object;
    g_cb_f[type] = func;
    g_cb_p[type] = parameter;
}

static void got_preview_image(void *param, GMT_TASK_OUTPUT *task_output)
{
    MOVIE_INFO_PRIVATE* ctx = (MOVIE_INFO_PRIVATE*)param;
    if (task_output->frame_info)
    {
        ekk_gmt_save_picture(task_output->frame_info, ctx->thumbnail_path);
    }
    g_task_output = task_output;
    g_cur_ctx = ctx;
    [g_mr performSelectorOnMainThread:@selector(On_Handle_Movie_Info) withObject:nil waitUntilDone:YES];
    g_cur_ctx = NULL;
    g_task_output = NULL;
}

+ (void)get_Movie_Info:(NSString*)file_path thumbnail_path:(NSString*)thumbnail_path thumbnail_width:(NSInteger)width thumbnail_height:(NSInteger)height thumbnail_time_at:(NSInteger)seconds target:(id)object got_info_callback:(SEL)func withObject:(id)parameter
{
    GMT_TASK_INPUT info = {0};
    MOVIE_INFO_PRIVATE* ctx = (MOVIE_INFO_PRIVATE*)ekk_malloc(sizeof(MOVIE_INFO_PRIVATE));
    ekk_memset(ctx, 0, sizeof(MOVIE_INFO_PRIVATE));
    ctx->path = (char*)ekk_malloc(EKK_MAX_URL_LEN);
    ekk_memset(ctx->path, 0, EKK_MAX_URL_LEN);
    [file_path getCString:ctx->path maxLength:EKK_MAX_URL_LEN encoding:NSUTF8StringEncoding];
    ctx->thumbnail_path = (char*)ekk_malloc(EKK_MAX_URL_LEN);
    ekk_memset(ctx->thumbnail_path, 0, EKK_MAX_URL_LEN);
    [thumbnail_path getCString:ctx->thumbnail_path maxLength:EKK_MAX_URL_LEN encoding:NSUTF8StringEncoding];
    ctx->target = object;
    ctx->selector = func;
    ctx->param = parameter;
    info.filepath = ctx->path;
    info.width = width;
    info.height = height;
    info.ts = (long long)seconds;
    info.notify_func = got_preview_image;
    info.notify_param = ctx;

    ekk_gmt_add_task(&info);
}

+ (MOVIE_INFO)current_Movie_Info
{
    return g_cur_movie_info;
}

+ (void)config_Subtitle:(CGRect*)prect fontEffect:(enum FontEffectType)font_effect  fontSize:(unsigned long)font_size fontColor:(unsigned long)font_color
{
    g_subtitle_bounds = *prect;
    g_font_effect = font_effect;
    g_font_size = font_size;
    g_font_color = font_color;
    if (g_view)
    {
        [g_view create_video_subtitle:SUBTITLE_TYPE_TEXT];
        [g_view set_video_subtitle_attribute:&g_subtitle_bounds fontEffect:g_font_effect fontSize:g_font_size fontColor:g_font_color];
    }
}

+ (void)hide_Subtitle:(BOOL)hidden
{
    g_hide_subtitle = hidden;
}


+ (BOOL)is_Subtitle_Hidden
{
    return g_hide_subtitle;
}

+ (void)On_Go_To_Back_Ground
{
    ekk_bool hard_dec_broken = ekk_false;	
	ekk_is_hard_dec_broken(&hard_dec_broken);
	if(hard_dec_broken)
	{
		(*((char*)NULL)) = NULL;
	}
    
    g_should_resume_bg = YES;
    if (g_state != E_PS_READY && g_state != E_PS_READY)
    {
        //ekk_enable_video_refresh(ekk_false);
        //ekk_enable_audio_refresh(ekk_false);
    }
    else
    {
        g_should_resume_bg = NO;
    }
}

+ (void)On_Resume_From_Back_Ground
{
    if (g_should_resume_bg)
    {
        //ekk_enable_video_refresh(ekk_true);
        //ekk_enable_audio_refresh(ekk_true);
    }
    g_should_resume_bg = NO;
}

+ (void)On_Will_Resign_Active
{
    g_should_resume_ls = YES;
    if (g_state != E_PS_READY && g_state != E_PS_READY)
    {
        ekk_enable_video_refresh(ekk_false);
        ekk_enable_audio_refresh(ekk_false);
    }
    else
    {
        g_should_resume_ls = NO;
    }
}

+ (void)On_Did_Become_Active
{
    if (g_should_resume_ls)
    {
        ekk_enable_video_refresh(ekk_true);
        ekk_enable_audio_refresh(ekk_true);
    }
    g_should_resume_ls = NO;
}

@end

@implementation Player_MainThread_Handler
@synthesize message;

- (void)On_Handle_Verbose
{
    switch (message)
    {
        case E_VM_PLAY:
            [Player_Model Play];
            break;
        default:
            break;
    }
}

- (void)On_SetUpVideoView
{
    setUpVideoView();
}

- (void)On_Handle_Movie_Info
{
    int i = 0;
    ekk_memset(&g_cur_movie_info, 0, sizeof(MOVIE_INFO));
    g_cur_movie_info.movie_path = [NSString stringWithCString:g_cur_ctx->path encoding:NSUTF8StringEncoding];
    long vd = -1;
    long ad = -1;
    if (g_task_output->is_valid) 
    {
        if (g_task_output->extract_info)
        {
            for (i = 0; i < g_task_output->extract_info->video_num; ++i)
            {
                if (g_task_output->extract_info->video_info[i]->width > 0)
                {
                    g_cur_movie_info.width = g_task_output->extract_info->video_info[i]->width;
                    g_cur_movie_info.height = g_task_output->extract_info->video_info[i]->height;
                    g_cur_movie_info.duration_in_seconds = g_task_output->extract_info->video_info[i]->duration;
                    vd = g_task_output->extract_info->video_info[i]->duration;
                }
            }
            for (i = 0; i < g_task_output->extract_info->audio_num; ++i)
            {
                if (g_task_output->extract_info->audio_info[i]->duration > 0)
                {
                    g_cur_movie_info.duration_in_seconds = g_task_output->extract_info->audio_info[i]->duration;
                    ad = g_task_output->extract_info->audio_info[i]->duration;
                }
            }
            g_cur_movie_info.duration_in_seconds = ad < 0 ? vd : (vd < 0 ? ad : (vd > ad ? ad : vd)); 
            if(g_task_output->extract_info->file_info->duration > 0)
            {
                g_cur_movie_info.duration_in_seconds = g_task_output->extract_info->file_info->duration;
            }
        }
        if (g_task_output->frame_info)
        {
            g_cur_movie_info.thumbnail_path = [NSString stringWithCString:g_cur_ctx->thumbnail_path encoding:NSUTF8StringEncoding];
        }
    }
    [g_cur_ctx->target performSelector:g_cur_ctx->selector withObject:g_cur_ctx->param];
    ekk_memset(&g_cur_movie_info, 0, sizeof(MOVIE_INFO));
    ekk_free(g_cur_ctx->path);
    ekk_free(g_cur_ctx->thumbnail_path);
    ekk_free(g_cur_ctx);
}

static void on_start_render_subtitle(void *param, int ret, char *path)
{
    if (ret == EKK_ERROR_NONE)
    {
        Player_MainThread_Handler* ph = *((Player_MainThread_Handler**)param);
        [ph performSelectorOnMainThread:@selector(Start_Render_Subtitle) withObject:nil waitUntilDone:NO];
    }
}

static void on_find_matched_subtitle(SUBTITLE_MATCH_CONTEXT* pcontext)
{
    if (pcontext->subtitle_net_url_count == 0 && pcontext->local_match_filepath_count > 0)
    {
        ekk_obj_start_subtitle(g_player_obj, 0, pcontext->local_match_filepath[0], pcontext->param, on_start_render_subtitle);
	}
}

- (void)Start_Render_Subtitle
{
    SUBTITLE_TEXT_ATTRIBUTE subatr = {0};
    
    subatr.fontsize = g_font_size;
    ekk_strcpy(subatr.fonttype,"Helvetica");
    subatr.x = (int)g_subtitle_bounds.origin.x;
    subatr.y = (int)g_subtitle_bounds.origin.y;
    subatr.rgba = g_font_color;
    ekk_obj_set_subtitle_attribute(g_player_obj, &subatr);
    
    if (subtitle_timer)
    {
        [subtitle_timer invalidate];
        //[subtitle_timer release];
        subtitle_timer = NULL;
    }
    subtitle_timer = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:@selector(On_Render_Subtitle) userInfo:nil repeats:YES];
}

- (void)On_SetUp_Subtitle
{
    if (g_view)
    {
        [g_view create_video_subtitle:SUBTITLE_TYPE_TEXT];
        [g_view set_video_subtitle_attribute:&g_subtitle_bounds fontEffect:g_font_effect fontSize:g_font_size fontColor:g_font_color];
    }
    
    if (ekk_obj_get_inner_subtitle_exist(g_player_obj))
    {
        [self Start_Render_Subtitle];
    }
    else
    {
        myself = self;
#if !TARGET_IPHONE_SIMULATOR
        ekk_obj_find_match_file(g_player_obj, (void*)&myself, on_find_matched_subtitle);
#endif
    }
}

- (void)On_Render_Subtitle
{
    if (!g_view)
    {
        return;
    }
    if (g_hide_subtitle)
    {
        [g_view render_video_subtitle_text:NULL location:NULL];
        return;
    }
    CGRect rect = {0};
	if(ekk_obj_get_inner_subtitle_exist(g_player_obj))
	{
        //load innner subtitle stream 
        ekk_obj_get_inner_subtitle_info(g_player_obj, &g_subtitle_info);
		if (g_subtitle_info.update_flag == 1)
        {
			rect.origin.x = (CGFloat)g_subtitle_info.left;
			rect.origin.y = (CGFloat)g_subtitle_info.top;
			rect.size.width = (CGFloat)(g_subtitle_info.right - g_subtitle_info.left);
			rect.size.height = (CGFloat)(g_subtitle_info.bottom - g_subtitle_info.top);
            [g_view render_video_subtitle_text:g_subtitle_info.subtitle_buf location:NULL/*&rect*/];
			if(g_subtitle_info.subtitle_buf)
			{
				ekk_free(g_subtitle_info.subtitle_buf);
				g_subtitle_info.subtitle_buf = NULL;
			}		
		}		
	} 
	else
	{
        // load out subtitle file
        ekk_obj_get_subtitle_info(g_player_obj, &g_subtitle_info);
        if (g_subtitle_info.update_flag == _SUBTITLE_HAVE_ONCE ) 
        {
            rect.origin.x = (CGFloat)g_subtitle_info.left;
			rect.origin.y = (CGFloat)g_subtitle_info.top;
			rect.size.width = (CGFloat)(g_subtitle_info.right - g_subtitle_info.left);
			rect.size.height = (CGFloat)(g_subtitle_info.bottom - g_subtitle_info.top);
			[g_view render_video_subtitle_text:g_subtitle_info.subtitle_buf location:NULL/*&rect*/];
		}	
		else if(g_subtitle_info.update_flag == _SUBTITLE_NO_CONTENT_ONCE)
		{
            [g_view render_video_subtitle_text:NULL location:NULL];
		}
	}
}

- (void)On_Stop_Render_Subtitle
{
    if (g_view)
    {
        [g_view render_video_subtitle_text:NULL location:NULL];
    }
    if (subtitle_timer)
    {
        [subtitle_timer invalidate];
        //[subtitle_timer release];
        subtitle_timer = NULL;
    }
}

- (void)On_Load_Url
{
    char* url = g_cur_url;
    if(ekk_obj_creat(&g_player_obj) != EKK_NONE)
    {
        [NSTimer scheduledTimerWithTimeInterval:0.005f target:self selector:@selector(On_Load_Url) userInfo:nil repeats:NO];
    }
    else if (g_player_obj)
    {
        //states
        ekk_obj_set_state_change_callback_function(g_player_obj, EKK_PS_OPENED, state_message_push_func, NULL);
        ekk_obj_set_state_change_callback_function(g_player_obj, EKK_PS_PLAY, state_message_push_func, NULL);
        ekk_obj_set_state_change_callback_function(g_player_obj, EKK_PS_PAUSE, state_message_push_func, NULL);
        ekk_obj_set_state_change_callback_function(g_player_obj, EKK_PS_CLOSING, state_message_push_func, NULL);
        ekk_obj_set_state_change_callback_function(g_player_obj, EKK_PS_CLOSED, state_message_push_func, NULL);
        ekk_obj_set_state_change_callback_function(g_player_obj, EKK_PS_STOPPING, state_message_push_func, NULL);
        ekk_obj_set_state_change_callback_function(g_player_obj, EKK_PS_SET_PLAY_EFFECT, state_message_push_func, NULL);
        ekk_obj_set_state_change_callback_function(g_player_obj, EKK_PS_RESTART_AUDIO_SERVICE, state_message_push_func, NULL);
        //video render
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_VIDEO_OPEN, video_open_handler, NULL);
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_VIDEO_CLOSE, video_close_handler, NULL);
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_VIDEO_RENDER, video_render_handler, NULL);
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_VIDEO_SET_PS, video_set_ps, NULL);
        //audio render
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_AUDIO_OPEN, audio_open_handler, NULL);
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_AUDIO_CLOSE, audio_close_handler, NULL);
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_AUDIO_RENDER, audio_render_handler, NULL);
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_AUDIO_FLUSH, audio_flush_handler, NULL);
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_AUDIO_REPLAY, audio_replay, NULL);
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_AUDIO_PAUSE, audio_pause, NULL);
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_AUDIO_GET_TS, audio_get_ts_handler, NULL);
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_AUDIO_GET_FRAME_COUNT, audio_get_frame_count_handler, NULL);
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_AUDIO_GET_PLAY_STATE, audio_get_play_state_handler, NULL);
        ekk_obj_set_render_callback_function(g_player_obj, EKK_RDR_AUDIO_SET_PS, audio_set_ps, NULL);
        if (ekk_obj_load(g_player_obj, url) == EKK_NONE)
        {
            //ekk load succeed
            g_state = E_PS_LOADING;
        }
    }
}

@end
